/**
 * Copyright (C) 2013 Orthogonal Labs, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.mattrigle;

import java.io.File;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * <p>Creates an AnimationDrawable from a GIF image.</p>
 *
 * @author Femi Omojola <femi@hipmob.com>
 */
public class GifAnimationDrawable extends AnimationDrawable implements CustomAnimation.TimerListener
{
	//==========================================================
	//Field 
	//==========================================================
	private boolean decoded;
	private GifDecoder mGifDecoder;
	private Bitmap mTmpBitmap;
	private int height, width;
	private int index = 0;
    private CustomAnimation anim = new CustomAnimation();
	
    private long foregroundElapsedTime = 0;

	private boolean pressed = false;
	private boolean is_runtime_message = false;
    private float messageElapsedTime = 0;
	private long fade_in_alert_message_time = 400L;
	private long fade_out_alert_message_time = 400L;
	private long cooldown_alert_message_time = 10000L;
	private int  alert_message_alpha = 0;
	private static enum AnimteState{FadeIn,Progress,FadeOut};
	private AnimteState anim_state = AnimteState.FadeIn;
	
	private View view = null;
    private Drawable alertDrawable = null;
    private int alert_width =0,alert_height=0;
    private String[] labels = null;
	private Rect foregroundRect = null;
	private Rect alertRect = new Rect();
    private Paint labelPaint = new Paint();
    private Point labelPoint = new Point(0,0);

    private float aw=1f;
    public void setSmoothScale(float aw)
    {
    	this.aw = aw;
        labelPaint.setTextSize(aw*25f);
		float aspectRatio = ((float)alertDrawable.getIntrinsicWidth())/alertDrawable.getIntrinsicHeight();
		alert_width = (int)(labelPaint.measureText(labels[0])*1.3);
		alert_height = (int)(alert_width*aspectRatio);

        labelPoint.x = alertRect.left  + (int)(labelPaint.measureText(labels[0])*0.2);
        labelPoint.y = alertRect.top+((int)(alertRect.height()*0.8)-(int)(labelPaint.measureText(labels[0])*0.15))/2;
        
    }
    
	//==========================================================
	//Constructor 
	//==========================================================
	public GifAnimationDrawable(View view,File f) throws IOException
	{
		this(view,f, false);
	}
	
	public GifAnimationDrawable(View view,InputStream is) throws IOException
	{
		this(view,is, false);
	}
	
	public GifAnimationDrawable(View view,File f, boolean inline) throws IOException
	{
	    this(view,new BufferedInputStream(new FileInputStream(f), 32768), inline);
	}
	
	@SuppressWarnings("deprecation")
	public GifAnimationDrawable(View view,InputStream is, boolean inline) throws IOException
	{
		super();
		this.view = view;
        Typeface face = Typeface.createFromAsset(view.getContext().getAssets(), "fonts/THA0085.ttf");
        labelPaint.setTypeface(face);
		String label = view.getResources().getString(R.string.alert_corner_touch);
		labels = label.split(",");
		alertDrawable =  view.getResources().getDrawable(R.raw.ballon_speak);
		
        labelPaint.setTextSize(32);
		float aspectRatio = ((float)alertDrawable.getIntrinsicWidth())/alertDrawable.getIntrinsicHeight();
		alert_width = (int)(labelPaint.measureText(labels[0])*1.3);
		alert_height = (int)(alert_width/aspectRatio);
		
        labelPaint.setColor(0xff383838);
		InputStream bis = is;
		if(!BufferedInputStream.class.isInstance(bis)) bis = new BufferedInputStream(is, 32768);
		decoded = false;
		mGifDecoder = new GifDecoder();
		mGifDecoder.read(bis);
		mTmpBitmap = mGifDecoder.getFrame(0);
		
		android.util.Log.v("GifAnimationDrawable", "===>Lead frame: ["+width+"x"+height+"; "+mGifDecoder.getDelay(0)+";"+mGifDecoder.getLoopCount()+"]");
		height = mTmpBitmap.getHeight();
    	width = mTmpBitmap.getWidth();
        addFrame(new BitmapDrawable(mTmpBitmap), mGifDecoder.getDelay(0));
        setOneShot(mGifDecoder.getLoopCount() != 0);
        setVisible(true, true);
        
		if(inline){
			loader.run();
		}else{
			new Thread(loader).start();
		}
	}

	//==========================================================
	//Properties 
	//==========================================================
	public boolean isDecoded(){ return decoded; }

	@Override
	public int getMinimumHeight(){ return height; }
	
	@Override
	public int getMinimumWidth(){ return width; }
	
	@Override
	public int getIntrinsicHeight(){ return height; }
	
	@Override
	public int getIntrinsicWidth(){ return width; }
	
	public void setForeground(Rect rect)
	{
		foregroundRect = rect;
		alertRect.left = foregroundRect.left+50;
		alertRect.top = foregroundRect.centerY() - alert_height + (int)(alert_height*0.4);
		alertRect.bottom = foregroundRect.centerY();
		alertRect.right = alertRect.left + (int)(alert_width*1.2);
		
		if(alertRect.top<10)
        {
        	alertRect.bottom += Math.abs(alertRect.top)/ +10;
        	alertRect.top = 10;
        }
		
        labelPoint.x = alertRect.left  + (int)(labelPaint.measureText(labels[0])*0.3);
        labelPoint.y = alertRect.top+((int)(alertRect.height()*0.5)-(int)(labelPaint.measureText(labels[0])*0.15))/2;
        
		alertDrawable.setBounds(alertRect);
	}
	
	//==========================================================
	//Process & Operand Method
	//==========================================================
	private Runnable loader = new Runnable(){
		@SuppressWarnings("deprecation")
		@Override
		public void run() 
		{
			mGifDecoder.complete();
			int i, n = mGifDecoder.getFrameCount(), t;
	        for(i=1;i<n;i++){
	            mTmpBitmap = mGifDecoder.getFrame(i);
	            t = mGifDecoder.getDelay(i);
	            android.util.Log.v("GifAnimationDrawable", "===>Frame "+i+": "+t+"]");
	            addFrame(new BitmapDrawable(mTmpBitmap), t);
	        }
	        decoded = true;
	    }
	};

	private Rect getSourceRect()
	{
		return new Rect(0,0,mGifDecoder.getFrame(index).getWidth(),mGifDecoder.getFrame(index).getHeight());
	}
	
	private Bitmap getFrameBitmap()
	{
		return mGifDecoder.getFrame(index);
	}
	
	private void startAlertMessage()
	{
		is_runtime_message = true;
		messageElapsedTime = 0;
		anim_state=AnimteState.FadeIn;
	}
	
	//==========================================================
	//Public Method
	//==========================================================
	@Override
	public void start() {
		
		if(!this.isDecoded())
			return;
		
		foregroundElapsedTime = 0;
		anim.setInterval(1000);
		anim.setListener(this);
		anim.StartAnimation();
		
		if(view!=null)
			view.postInvalidate();
	}

	@Override
	public void stop() {
		if(anim!=null)
			anim.StopAnimation();
		super.stop();
	}

	public void finish()
	{
		try{
			decoded = false;
			if(decoded)
			{
				if(alertDrawable!=null)
					((BitmapDrawable)this.alertDrawable).getBitmap().recycle();
				if(mTmpBitmap!=null)
					this.mTmpBitmap.recycle();
			}
		}
		catch(Exception e){}
	}
	
    // ==========================================================
	// Event Method
	// ==========================================================
	public boolean onTouch(int action, int x, int y) {
		if(!isDecoded())
			return false;
		if (action == MotionEvent.ACTION_DOWN) {
			if (foregroundRect.left<x&&foregroundRect.right>x&&
				foregroundRect.top<y&&foregroundRect.bottom>y) {
				if(!pressed)
				{
					startAlertMessage();
					pressed = true;
				}
				return true;
			}
		}	
		if (action == MotionEvent.ACTION_UP||action == MotionEvent.ACTION_CANCEL) {
			pressed = false;
		}
		return false;
	}
	
	public void Draw(Canvas canvas) {
		if(this.isDecoded())
		{
			
			canvas.drawBitmap(getFrameBitmap(),getSourceRect(),foregroundRect, new Paint());
			if(pressed||is_runtime_message)
			{
				if(view!=null)
				{
					Log.e("Math","Draw(Canvas canvas) ;"+alert_message_alpha);
				}
				
				alertDrawable.setAlpha(alert_message_alpha);
				labelPaint.setAlpha(alert_message_alpha);

				alertDrawable.draw(canvas);
				for(int i=0;i<labels.length;i++)
					canvas.drawText(labels[i], labelPoint.x, labelPoint.y+(aw*18*i), labelPaint);
			}
			
		}
	}

	@Override
	public void onTimeUpdate(CustomAnimation obj, long totalTime, long deltaTime) {
		
		if(!isDecoded())
			return;
		
		foregroundElapsedTime += deltaTime;
		if(foregroundElapsedTime>getDuration(index))
		{
			while(foregroundElapsedTime>getDuration(index))
			{
				foregroundElapsedTime -= getDuration(index);
				index = ((index+1)%getNumberOfFrames());
			}
			
			if(view!=null)
				view.postInvalidate();
		}
		
		if(pressed||is_runtime_message)
		{Log.e("Math","if(pressed||is_runtime_message)"+messageElapsedTime);
		
			messageElapsedTime += deltaTime;
			switch(anim_state)
			{
				case FadeIn:
					alert_message_alpha = (int)((messageElapsedTime/(float)fade_in_alert_message_time)*255f);
					if(messageElapsedTime>fade_in_alert_message_time)
					{
						Log.e("Math","anim_state = AnimteState.Progress;");
						messageElapsedTime = 0;
						anim_state = AnimteState.Progress;
					}
					break;
				case Progress:
					if(messageElapsedTime>cooldown_alert_message_time)
					{
						Log.e("Math","anim_state = AnimteState.FadeOut");
						messageElapsedTime = cooldown_alert_message_time;
						if(!pressed)
						{
							messageElapsedTime = 0;
							anim_state = AnimteState.FadeOut;
						}
					}
					break;
				case FadeOut:
					alert_message_alpha = (int)(((float)(fade_out_alert_message_time - messageElapsedTime)/(float)fade_out_alert_message_time)*255f);
					if(messageElapsedTime>fade_out_alert_message_time)
					{
						Log.e("Math","anim_state = AnimteState.FadeIn;");
						anim_state = AnimteState.FadeIn;
						is_runtime_message = false;
						pressed = false;
					}
					break;
			}
			if(alert_message_alpha>255)
				alert_message_alpha=255;
			
			if(view!=null)
			{
				Log.e("Math","view.postInvalidate();");
				view.postInvalidate();
			}
		}
	}

}
